package com.yc.cloud.admin.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yc.cloud.admin.common.UmsAdminConstants;
import com.yc.cloud.admin.dto.request.FaceAddFileReqDTO;
import com.yc.cloud.admin.dto.request.UmsAdminCreateParam;
import com.yc.cloud.admin.dto.request.UmsAdminUpdateParam;
import com.yc.cloud.admin.dto.request.UpdateAdminPasswordParam;
import com.yc.cloud.admin.dto.response.FaceAddFileRespDTO;
import com.yc.cloud.admin.service.FaceRecognitionService;
import com.yc.cloud.admin.service.UmsAdminCacheService;
import com.yc.cloud.admin.service.UmsAdminService;
import com.yc.cloud.admin.service.UmsResourceCacheService;
import com.yc.cloud.admin.vo.UmsAdminVo;
import com.yc.cloud.common.oss.entity.OssFile;
import com.yc.cloud.common.basic.dto.BasePageReqDTO;
import com.yc.cloud.common.basic.exception.Asserts;
import com.yc.cloud.common.basic.utils.RequestUtil;
import com.yc.cloud.common.orm.CommonPage;
import com.yc.cloud.common.oss.service.OssFileService;
import com.yc.cloud.entity.UmsAdmin;
import com.yc.cloud.entity.UmsAdminLoginLog;
import com.yc.cloud.entity.UmsResource;
import com.yc.cloud.entity.UmsRole;
import com.yc.cloud.mapper.UmsAdminLoginLogMapper;
import com.yc.cloud.mapper.UmsAdminMapper;
import com.yc.cloud.mapper.UmsResourceMapper;
import com.yc.cloud.admin.service.UmsRoleService;
import com.yc.cloud.security.dto.AdminUserDetails;
import com.yc.cloud.security.utils.AdminUtils;
import com.yc.cloud.security.utils.JwtTokenUtil;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import lombok.val;
import org.springframework.beans.BeanUtils;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.io.File;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 * 后台用户表 服务实现类
 * </p>
 *
 * @author JackGu
 * @since 2022-09-11
 */
@Service
@Slf4j
public class UmsAdminServiceImpl extends ServiceImpl<UmsAdminMapper, UmsAdmin> implements UmsAdminService {

    @Resource
    private UmsAdminCacheService adminCacheService;
    @Resource
    private UmsResourceCacheService umsResourceCacheService;
    @Resource
    private JwtTokenUtil jwtTokenUtil;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Resource
    private UmsAdminMapper umsAdminMapper;

    @Resource
    private UmsAdminLoginLogMapper umsAdminLoginLogMapper;

    @Resource
    private UmsResourceMapper resourceMapper;

    @Resource
    private UmsRoleService roleService;

    @Resource
    private OssFileService ossFileService;

    @Resource
    private FaceRecognitionService faceRecognitionService;


    @Override
    public CommonPage<UmsAdminVo> list(BasePageReqDTO queryParam) {
        val query = new QueryWrapper<UmsAdmin>();
        IPage<UmsAdmin> page;
        //排序
        if (StrUtil.isNotEmpty(queryParam.getSortBy())) {
            if (BasePageReqDTO.ORDER_DESC.equals(queryParam.getOrder())) {
                query.orderByDesc(UmsAdmin.ID);
            } else if (BasePageReqDTO.ORDER_ASC.equals(queryParam.getOrder())) {
                query.orderByAsc(UmsAdmin.ID);
            }
        }
        //模糊查询
        val keyword = queryParam.getKeyword();
        if (StrUtil.isNotEmpty(keyword)) {
            query.and(queryWrapper -> {
                queryWrapper.like(UmsAdmin.USERNAME, keyword).or().like(UmsAdmin.TRUE_NAME, keyword);
            });
        }
        //分页
        if (queryParam.getPage()) {
            page = new Page<>(queryParam.getPageNum(), queryParam.getPageSize(), true);
        } else {
            page = new Page<>(queryParam.getPageNum(), umsAdminMapper.selectCount(query), true);
        }
        IPage<UmsAdmin> pageResult = umsAdminMapper.selectPage(page, query);
        
        // 转换为VO对象
        CommonPage<UmsAdmin> commonPage = CommonPage.restPage(pageResult);
        CommonPage<UmsAdminVo> result = new CommonPage<>();
        result.setPageNum(commonPage.getPageNum());
        result.setPageSize(commonPage.getPageSize());
        result.setTotalPage(commonPage.getTotalPage());
        result.setTotal(commonPage.getTotal());
        result.setList(commonPage.getList().stream().map(this::convertToVo).collect(Collectors.toList()));
        
        return result;
    }

    /**
     * 转换为VO对象
     */
    private UmsAdminVo convertToVo(UmsAdmin admin) {
        UmsAdminVo vo = new UmsAdminVo();
        BeanUtils.copyProperties(admin, vo);
        
        // 转换头像文件ID为URL
        if (StrUtil.isNotEmpty(admin.getIcon())) {
            String iconUrl = ossFileService.getOssFileUrl(admin.getIcon());
            vo.setIconUrl(iconUrl);
        }
        
        return vo;
    }

    @Override
    public String queryByUserNameAndPassword(String username, String password) {
        String token = null;
        //密码需要客户端加密后传递
        try {
            adminCacheService.delByUserName(username);
            UserDetails userDetails = loadUserByUsername(username);
            if (!passwordEncoder.matches(password, userDetails.getPassword())) {
                Asserts.fail("密码不正确");
            }
            if (!userDetails.isEnabled()) {
                Asserts.fail("帐号已被禁用");
            }
            UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
            SecurityContextHolder.getContext().setAuthentication(authentication);
            token = jwtTokenUtil.generateToken(userDetails);
            updateLoginTimeByUsername(username);
            insertLoginLog(username);
        } catch (AuthenticationException e) {
            log.warn("登录异常:{}", e.getMessage());
        }
        return token;
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        //获取用户信息
        UmsAdmin admin = getAdminByUsername(username);
        if (admin != null) {
            List<UmsResource> resourceList = getResourceList(admin);
            return new AdminUserDetails(admin, resourceList);
        }
        throw new UsernameNotFoundException("用户名或密码错误");
    }

    @Override
    public UmsAdmin queryByUserName(String username) {
        val query = new QueryWrapper<UmsAdmin>();
        query.eq("username", username);
        return umsAdminMapper.selectOne(query);
    }

    @Override
    public UmsAdmin getAdminByUsername(String username) {
        UmsAdmin admin = adminCacheService.getByUserName(username);
        if (admin != null) {
            return admin;
        }
        val queryMap = new HashMap<String, Object>(1);
        queryMap.put("username", username);
        List<UmsAdmin> adminList = umsAdminMapper.selectByMap(queryMap);
        if (adminList != null && adminList.size() > 0) {
            admin = adminList.get(0);
            adminCacheService.setByUserName(username, admin);
            return admin;
        }
        return null;
    }

    @Override
    public UmsAdmin getAdmin() {
        val username = AdminUtils.getCurrentUserName();
        UmsAdmin admin = adminCacheService.getByUserName(username);
        if (admin != null) {
            return admin;
        }
        val queryMap = new HashMap<String, Object>(1);
        queryMap.put("username", username);
        List<UmsAdmin> adminList = umsAdminMapper.selectByMap(queryMap);
        if (adminList != null && adminList.size() > 0) {
            admin = adminList.get(0);
            adminCacheService.setByUserName(username, admin);
            return admin;
        }
        return null;
    }

    @Override
    public List<UmsResource> getResourceList(UmsAdmin umsAdmin) {
        List<UmsResource> resourceList = umsResourceCacheService.getByUserName(umsAdmin.getUsername());
        if (CollUtil.isNotEmpty(resourceList)) {
            return resourceList;
        }
        //TODO 待测试
        resourceList = resourceMapper.getResourceList(umsAdmin.getId());
        if (CollUtil.isNotEmpty(resourceList)) {
            umsResourceCacheService.setByUserName(umsAdmin.getUsername(), resourceList);
        }
        return resourceList;
    }

    @Override
    public UmsAdmin register(UmsAdminCreateParam umsAdminParam) {
        UmsAdmin umsAdmin = new UmsAdmin();
        BeanUtils.copyProperties(umsAdminParam, umsAdmin);
        umsAdmin.setCreateTime(LocalDateTime.now());
        umsAdmin.setStatus(UmsAdminConstants.STATUS_ENABLE);
        //将密码进行加密操作
        String encodePassword = passwordEncoder.encode(umsAdmin.getPassword());
        umsAdmin.setPassword(encodePassword);
//        umsAdmin.setIcon(icon);
        umsAdminMapper.insert(umsAdmin);
        return umsAdmin;
    }

    @Override
    public void logout() {
        adminCacheService.delByUserName(AdminUtils.getCurrentUserName());
        umsResourceCacheService.delByUserName(AdminUtils.getCurrentUserName());
    }

    @Override
    public int updatePassword(UpdateAdminPasswordParam param) {
        if (StrUtil.isEmpty(param.getUsername()) || StrUtil.isEmpty(param.getNewPassword())) {
            return -1;
        }
        val query = new QueryWrapper<UmsAdmin>();
        query.eq("username", param.getUsername());
        val adminList = umsAdminMapper.selectList(query);
        if (CollUtil.isEmpty(adminList)) {
            return -2;
        }
        UmsAdmin umsAdmin = adminList.get(0);
        // 判断当前操作者是否为管理员角色：管理员可跳过旧密码校验，其他角色必须校验
        boolean requireOldPassword = true;
        UmsAdmin current = getAdmin();
        if (current != null) {
            List<UmsRole> roles = roleService.getRoleList(current.getId());
            if (AdminUtils.isSuperAdminByRoles(roles)) {
                requireOldPassword = false;
            }
        }

        if (requireOldPassword) {
            if (StrUtil.isEmpty(param.getOldPassword()) || !passwordEncoder.matches(param.getOldPassword(), umsAdmin.getPassword())) {
                return -3;
            }
        }
        umsAdmin.setPassword(passwordEncoder.encode(param.getNewPassword()));
        umsAdminMapper.updateById(umsAdmin);
        
        // 清除Redis缓存（缓存的key是基于username的）
        adminCacheService.delByUserName(umsAdmin.getUsername());
        
        return 1;
    }

    @Override
    public int update(Long id, UmsAdminUpdateParam admin) {
        UmsAdmin rawAdmin = umsAdminMapper.selectById(id);
        if (rawAdmin == null) {
            return -1;
        }
        
        // 保存旧的头像ID，用于后续比较
        String oldIconId = rawAdmin.getIcon();
        
        // 更新用户信息（不包含密码，密码使用单独的重置密码接口）
        // 直接设置字段，允许更新为空值（清空字段）
        rawAdmin.setIcon(admin.getIcon());
        rawAdmin.setEmail(admin.getEmail());
        rawAdmin.setMobile(admin.getMobile());
        rawAdmin.setTrueName(admin.getTrueName());
        rawAdmin.setNote(admin.getNote());
        
        // 检查是否更新了头像，如果更新了则处理人脸识别
        if (StrUtil.isNotBlank(rawAdmin.getIcon()) && !rawAdmin.getIcon().equals(oldIconId)) {
            processFaceRecognition(rawAdmin);
        }
        
        int count = umsAdminMapper.updateById(rawAdmin);
        
        // 清除Redis缓存（缓存的key是基于username的）
        adminCacheService.delByUserName(rawAdmin.getUsername());
        
        return count;
    }

    @Override
    public String refreshToken(String oldToken) {
        return jwtTokenUtil.refreshHeadToken(oldToken);
    }

    @Override
    public UmsAdmin create(UmsAdminCreateParam param) {
        UmsAdmin umsAdmin = new UmsAdmin();
        BeanUtils.copyProperties(param, umsAdmin);
        umsAdmin.setCreateTime(LocalDateTime.now());
        umsAdmin.setStatus(UmsAdminConstants.STATUS_ENABLE);
        //将密码进行加密操作
        String encodePassword = passwordEncoder.encode(umsAdmin.getPassword());
        umsAdmin.setPassword(encodePassword);
        
        // 先保存用户，获取用户ID
        int count = umsAdminMapper.insert(umsAdmin);
        if (count <= 0) {
            return null;
        }
        
        // 处理人脸识别（如果设置了头像）
        processFaceRecognition(umsAdmin);
        
        // 清除Redis缓存（新用户通常不会有缓存，但为了保险起见仍然清除）
        adminCacheService.delByUserName(umsAdmin.getUsername());
        
        return umsAdmin;
    }


    /**
     * 根据用户名修改登录时间
     */
    private void updateLoginTimeByUsername(String username) {
        val admin = queryByUserName(username);
        if (admin != null) {
            admin.setLoginTime(LocalDateTime.now());
            umsAdminMapper.updateById(admin);
        }
    }

    private void insertLoginLog(String username) {
        UmsAdmin admin = getAdminByUsername(username);
        if (admin == null) {
            return;
        }
        UmsAdminLoginLog loginLog = new UmsAdminLoginLog();
        loginLog.setAdminId(admin.getId());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        if (attributes != null) {
            HttpServletRequest request = attributes.getRequest();
            loginLog.setIp(RequestUtil.getRequestIp(request));
        }
        umsAdminLoginLogMapper.insert(loginLog);
    }

    /**
     * 处理用户人脸识别
     * 如果用户设置了头像(icon)，则从OSS获取文件并调用人脸识别服务添加人脸
     * 
     * @param umsAdmin 用户对象（必须已经有ID）
     */
    private void processFaceRecognition(UmsAdmin umsAdmin) {
        // 检查用户是否设置了头像
        if (StrUtil.isBlank(umsAdmin.getIcon())) {
            log.debug("用户未设置头像，跳过人脸识别处理: userId={}", umsAdmin.getId());
            return;
        }
        
        // 从OSS获取头像文件
        OssFile ossFile = ossFileService.getByFileIdFromDb(umsAdmin.getIcon());
        if (ossFile == null || StrUtil.isBlank(ossFile.getPath())) {
            log.warn("无法获取用户头像文件，跳过人脸识别处理: userId={}, iconFileId={}", 
                    umsAdmin.getId(), umsAdmin.getIcon());
                    return;
        }
        File faceImageFile = new File(ossFile.getPath());
        try {
            // 构建人脸识别请求参数
            // 优先使用用户名，如果为空则使用真实姓名
            String personName = StrUtil.isNotBlank(umsAdmin.getUsername()) 
                    ? umsAdmin.getUsername() 
                    : umsAdmin.getTrueName();
            
            FaceAddFileReqDTO faceReqDTO = FaceAddFileReqDTO.builder()
                    .personId("user_" + umsAdmin.getId())
                    .personName(personName)
                    .metaInfo(null)  // 扩展信息暂不使用，后续可以添加部门、角色等信息
                    .build();
            
            // 调用人脸识别服务添加/更新人脸
            FaceAddFileRespDTO faceResult = faceRecognitionService.addFaceFile(faceImageFile, faceReqDTO);
            
            // 处理人脸识别结果
            if (faceResult != null && faceResult.isSuccess()) {
                // 更新用户的人脸ID
                umsAdmin.setFaceId(faceResult.getFaceId());
                umsAdminMapper.updateById(umsAdmin);
                log.info("用户人脸识别处理成功: userId={}, faceId={}", 
                        umsAdmin.getId(), faceResult.getFaceId());
            } else {
                log.error("用户人脸识别处理失败: userId={}, message={}", 
                        umsAdmin.getId(), faceResult != null ? faceResult.getMsg() : "未知错误");
            }
            
        } catch (Exception e) {
            log.error("用户人脸识别处理异常: userId={}", umsAdmin.getId(), e);
            // 人脸识别异常不影响用户创建/更新，只记录日志
        }
    }

    @Override
    public boolean delete(Long id) {
        if (id == null) {
            log.warn("删除用户失败: ID为空");
            return false;
        }

        // 先查询用户信息
        UmsAdmin umsAdmin = umsAdminMapper.selectById(id);
        if (umsAdmin == null) {
            log.warn("删除用户失败: 用户不存在, userId={}", id);
            return false;
        }

        // 如果用户有关联的人脸数据，先删除人脸
        if (StrUtil.isNotBlank(umsAdmin.getFaceId())) {
            try {
                log.info("删除用户关联的人脸数据: userId={}, faceId={}", id, umsAdmin.getFaceId());
                Boolean faceDeleted = faceRecognitionService.deleteFace(umsAdmin.getFaceId());
                if (Boolean.TRUE.equals(faceDeleted)) {
                    log.info("用户人脸数据删除成功: userId={}, faceId={}", id, umsAdmin.getFaceId());
                } else {
                    log.warn("用户人脸数据删除失败: userId={}, faceId={}", id, umsAdmin.getFaceId());
                }
            } catch (Exception e) {
                // 人脸删除失败不影响用户删除，只记录日志
                log.error("删除用户人脸数据异常: userId={}, faceId={}", id, umsAdmin.getFaceId(), e);
            }
        }

        // 删除用户
        int count = umsAdminMapper.deleteById(id);
        
        // 清除Redis缓存
        if (count > 0) {
            adminCacheService.delByUserName(umsAdmin.getUsername());
            log.info("用户删除成功: userId={}, username={}", id, umsAdmin.getUsername());
        }

        return count > 0;
    }

}
